% ParamImgSys: Parameters of the imaging system
%
% PARAM = ParamImgSys(): Return a structure PARAM contaning the parameters
% of the imaging system using the default imaging configuration.
%
% PARAM = ParamImgSys(CONF): Return a structure PARAM contaning the 
% parameters of the imaging system using the experimental configuration
% specified in the structure CONF which contains the following fields:
%   'obj'   -> First objective of the imaging system
%   'micro' -> Microscope objective
%   'cam'   -> Camera
%
% T. Vanderbruggen, 2013
function param = ParamImgSys(varargin)
    % ---------------------------------------------------------------------
    % Parsing inputs
    % ---------------------------------------------------------------------
    if nargin == 0 % Use default experimental configuration
        config = GetImgConfig(1);
    elseif nargin == 1
        if isstruct(varargin{1})
            config = varargin{1};
        elseif isnumeric(varargin{1})
            config = GetImgConfig(varargin{1});  
        else
            error('ParamImgSys: Unauthorized input type');
        end
    else % narargin > 1
        error('ParamImgSys: Too many input arguments');
    end
    
    % ---------------------------------------------------------------------
    % Get parameters of the imaging system
    % ---------------------------------------------------------------------
    
    %
    % Glass cell
    %
    param.trans_cell_780  = 0.97;     % Transmission of a single window (both faces) at 780 nm
    param.trans_cell_1529 = 0.99;     % Transmission of a single window (both faces) at 1529 nm
    param.trans_cell_1560 = 0.99;     % Transmission of a single window (both faces) at 1560 nm
    
    %
    % Dichroic
    %
    param.reflec_dich_780  = 1.0;     % Reflection of the dichroic at 780 nm
                                      % TO BE COMPLETED !!
    %
    % Objective
    %
    if ~ischar(config.obj)
        error('ParamImgSys: The objective must be specified by a string');
    else
        % No objective. Use default values
        if strcmpi(config.obj,'none') 
            param.mag_obj    = 1.0;	  % Magnification 
            param.na_obj_in  = 1.0;   % Input numerical aperture
            param.trans_obj  = 1.0;   % Transmission at 780 nm
        % Telecentric objective (Xenoplan Telecentric 1:2, Schneider Optics)
        elseif strcmpi(config.obj,'Xenonplan1:2') 
            param.mag_obj    = 0.50;  % Magnification telecentric objective
            param.na_obj_in  = 0.14;  % Input numerical aperture telecentric objective
            param.trans_obj  = 0.90;  % Transmission of the objective at 780 nm
        else
            error('ParamImgSys: Unknown objective');
        end
        
        % Output numerical apperture
        param.na_obj_out = param.na_obj_in/param.mag_obj;
    end
    
    % Test some properties to cacth obvious mistakes in parameter inputs
    % 0 <= NA <= 1
    if param.na_obj_in < 0 || param.na_obj_in > 1
        error('ParamImgSys: Objective input NA must be between 0 and 1');
    end
    % 0 <= Tranmission <= 1
    if param.trans_obj < 0 || param.trans_obj > 1
        error('ParamImgSys: Objective transmission must be between 0 and 1');
    end
    
    %
    % Microscope objective
    %
    if ~ischar(config.micro)
        error('ParamImgSys: The microscope objective must be specified by a string');
    else
        if strcmpi(config.micro,'none') % No objective. Use default values
            param.mag_micro   = 1.0;    % Magnification 
            param.na_micro_in = 1.0;    % Input numerical aperture
            param.trans_micro = 1.0;    % Transmission at 780 nm
        elseif strcmpi(config.micro,'N4X-PF') % Nikon N4X-PF
            param.mag_micro   = 4.0;    % Magnification 
            param.na_micro_in = 0.13;   % Input numerical aperture
            param.trans_micro = 0.76;   % Transmission at 780 nm
                                        % --> UNKNOWN: Use transmission for the N10X-PF
        elseif strcmpi(config.micro,'N10X-PF') % Nikon N10X-PF
            param.mag_micro   = 10.0;   % Magnification 
            param.na_micro_in = 0.30;   % Input numerical aperture
            param.trans_micro = 0.76;   % Transmission at 780 nm -> UNKNOWN !
        else
            error('ParamImgSys: Unknown microscope objective');
        end
    end
    
    % Test some properties to cacth obvious mistakes in parameter inputs
    % 0 <= NA <= 1
    if param.na_micro_in < 0 || param.na_micro_in > 1
        error('ParamImgSys: Microscope input NA must be between 0 and 1');
    end
    % 0 <= Tranmission <= 1
    if param.trans_micro < 0 || param.trans_micro > 1
        error('ParamImgSys: Microscope transmission must be between 0 and 1');
    end
    
    %
    % Camera
    %
    if ~ischar(config.cam)
        error('ParamImgSys: The camera must be specified by a string');
    else
        if strcmpi(config.cam,'pco.pixelfly') % pco.pixelfly usb, CCD camera
            CCDbin = config.binning;
            param.px_size = CCDbin*6.45E-6; % Pixel size (m)
            param.long_px_nb = 1392/CCDbin;    % Number of horizontal pixels
            param.short_px_nb = 1040/CCDbin;    % Number of vertical pixels
            param.qe      = 0.11;    % Quantum efficiency standard mode at 780 nm
            param.qe_ll   = 0.23;    % Quantum efficiency low light mode at 780 nm
        else
            error('ParamImgSys: Unknown camera');
        end
    end
    
    % Test some properties to cacth obvious mistakes in parameter inputs
    % 0 <= QE <= 1
    if param.qe < 0 || param.qe > 1 || param.qe_ll < 0 || param.qe_ll > 1
        error('ParamImgSys: Camera QE must be between 0 and 1');
    end
    % Upper limit on pixel size
    if param.px_size > 1E-4 % m
        error('ParamImgSys: Pixel size must be <= 100 um');
    end
    
    % ---------------------------------------------------------------------
    % Calculate overall parameters of the imaging system
    % ---------------------------------------------------------------------
    
    % Magnification 
    param.mag = param.mag_obj*param.mag_micro;
    
    % Input numerical aperture
    if param.na_obj_out < param.na_micro_in % The NA is limited by the first objective
        param.na_in = param.na_obj_in;
    else % The NA is limited by the microscope objective
        param.na_in = param.na_micro_in*param.mag_obj;
    end
    
    % Resolution in object space (m)
    lambda = 780E-9;    % Wavelength (m)
    param.resolution = 1.22*lambda/(2*param.na_in);
    
    % Transmission at 780 nm
    param.trans780 = param.trans_cell_780*param.reflec_dich_780*param.trans_obj*param.trans_micro;
    
    % Collection efficiency of the imaging system
    theta = asin(param.na_in);
    Omega = 2*pi*(1-cos(theta)); % Solid angle at the input
    param.coll_eff = param.qe * param.trans780 * Omega/(4*pi);
end

